package com.imooc.reader.portal.service.impl;

import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.imooc.reader.portal.dto.SmsResult;
import com.imooc.reader.portal.entity.Member;
import com.imooc.reader.portal.entity.MemberReadState;
import com.imooc.reader.portal.entity.VerificationCode;
import com.imooc.reader.portal.mapper.MemberMapper;
import com.imooc.reader.portal.mapper.MemberReadStateMapper;
import com.imooc.reader.portal.mapper.VerificationCodeMapper;
import com.imooc.reader.portal.service.MemberService;
import com.imooc.reader.portal.service.impl.exception.BusinessException;
import com.imooc.reader.portal.utils.SmsUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Random;

@Service
public class MemberServiceImpl implements MemberService {
    @Resource
    private VerificationCodeMapper verificationCodeMapper;
    @Resource
    private SmsUtils smsUtils;
    @Resource
    private MemberMapper memberMapper;
    @Resource
    private MemberReadStateMapper memberReadStateMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void sendVCode(String mobile) {
        String vcode = this.generateRandomCode(4);
        try {
            // 将同一个mobile已发送的验证码设置为过期
            QueryWrapper wrapper = new QueryWrapper<>();
            wrapper.eq("mobile", mobile);
            wrapper.eq("state", 0);
            List<VerificationCode> codeList = verificationCodeMapper.selectList(wrapper);
            for (VerificationCode code : codeList) {
                code.setState(2);
                verificationCodeMapper.updateById(code);
            }

            // 采用mock方式发送验证码，发送成功时：<code,message>={"OK", "OK"}
            SmsResult smsResult = smsUtils.sendVerifyCode(mobile, vcode);
            if (!smsResult.getCode().equals("OK")) {
                throw new BusinessException(smsResult.getCode(), smsResult.getMessage());
            }

            VerificationCode verificationCode = new VerificationCode();
            verificationCode.setMobile(mobile);
            // 产生4位随机数
            verificationCode.setVerificationCode(vcode);
            verificationCode.setState(0);
            verificationCode.setSendTime(new Date());
            // 设置验证码过期时间为5分钟
            verificationCode.setExpireTime(this.calculateExpireTime(5));
            verificationCodeMapper.insert(verificationCode);
        } catch (Exception e) {
            throw new BusinessException(e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Member register(String mobile, String vcode) {
        Date now = new Date();
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.ge("expire_time", now);
        wrapper.eq("state", 0);
        wrapper.eq("mobile", mobile);
        wrapper.eq("verification_code", vcode);
        // 按照发送时间倒序排序，获取最近发送验证码的数据
        wrapper.orderByDesc("send_time");
        List<VerificationCode> codeList = verificationCodeMapper.selectList(wrapper);
        if (codeList.size() > 0) {
            Member member = null;
            QueryWrapper<Member> memberQueryWrapper = new QueryWrapper<>();
            memberQueryWrapper.eq("mobile", mobile);
            List<Member> membersList = memberMapper.selectList(memberQueryWrapper);
            if (membersList.size() > 0) {
                member = membersList.get(0);
            } else {
                member = new Member();
                member.setMobile(mobile);
                member.setNickname("慕粉" + mobile.substring(6, 10));
                member.setCreateTime(now);
                memberMapper.insert(member);
            }
            VerificationCode verificationCode = codeList.get(0);
            verificationCode.setMemberId(member.getMemberId());
            // 将state状态修改为已验证的状态，即为1
            verificationCode.setState(1);
            verificationCode.setVerifyTime(now);
            verificationCodeMapper.updateById(verificationCode);
            return member;
        } else {
            throw new BusinessException("INVALIDE_VERIFICATION_CODE", "验证码无效");
        }

    }

    @Override
    public Member selectById(Long memberId) {
        Member member = memberMapper.selectById(memberId);
        return member;
    }

    @Override
    public MemberReadState selectMemberReadState(Long memberId, Long bookId) {
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.eq("member_id", memberId);
        wrapper.eq("book_id", bookId);
        MemberReadState memberReadState = memberReadStateMapper.selectOne(wrapper);
        return memberReadState;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public MemberReadState updateMemberReadState(Long memberId, Long bookId, Integer readState) {
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.eq("member_id", memberId);
        wrapper.eq("book_id", bookId);
        MemberReadState memberReadState = memberReadStateMapper.selectOne(wrapper);
        if (memberReadState == null) {
            memberReadState = new MemberReadState();
            memberReadState.setReadState(readState);
            memberReadState.setBookId(bookId);
            memberReadState.setMemberId(memberId);
            memberReadState.setCreateTime(new Date());
            memberReadStateMapper.insert(memberReadState);
        } else {
            memberReadState.setReadState(readState);
            memberReadStateMapper.updateById(memberReadState);
        }
        return memberReadState;
    }

    /**
     * 产生随机码
     * @param codeLength 指定随机码的位数
     * @return
     */
    private String generateRandomCode(int codeLength) {
        Random random = new Random();
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < codeLength; i++) {
            buffer.append(random.nextInt(10));
        }
        return buffer.toString();
    }

    /**
     * 根据分钟数设置过期时间
     * @param minutes 设置要过期的分钟数
     * @return
     */
    private Date calculateExpireTime(int minutes) {
        long currentTimeMillis = System.currentTimeMillis();
        long expireTimeMillis = currentTimeMillis + (minutes * 60 * 1000);
        return new Date(expireTimeMillis);
    }
}
